#!/usr/bin/perl
#
# This test performs access checks for a file.
#

use Test;

BEGIN {
    $basedir = $0;
    $basedir =~ s|(.*)/[^/]*|$1|;

    $isnfs = `stat -f --print %T $basedir`;

    $test_count = 15;
    if ( $isnfs ne "nfs" ) {
        $test_count++;
    }

    plan tests => $test_count;
}

#
# Clean up from a previous run
#
system "rm -f $basedir/temp_file 2>&1";
system "rm -f $basedir/temp_file2 2>&1";
system "rm -f $basedir/temp_file3 2>&1";

#
# Create the temp files
#
system
  "dd if=/dev/zero of=$basedir/temp_file count=2 ibs=1024 2>&1 > /dev/null";
system
  "dd if=/dev/zero of=$basedir/temp_file2 count=2 ibs=1024 2>&1 > /dev/null";
system
  "dd if=/dev/zero of=$basedir/temp_file3 count=2 ibs=1024 2>&1 > /dev/null";
system "chmod 775 $basedir/temp_file 2>&1 > /dev/null";
system "chmod 775 $basedir/temp_file2 2>&1 > /dev/null";
#
# Change the context for the file the good domain only has access to.
#
system "chcon -t fileop_file_t $basedir/temp_file 2>&1 > /dev/null";
#
# Change the context for the r/w file for the bad domain
#
system "chcon -t nofileop_rw_file_t $basedir/temp_file2 2>&1 > /dev/null";

#
# Change the context for the read-only access file for the bad domain
#
system "chcon -t nofileop_ra_file_t $basedir/temp_file3 2>&1 > /dev/null";

#
# Change the context of the test executable
#
system "chcon -t fileop_exec_t $basedir/wait_io 2>&1 > /dev/null";

#
# Get the SID of the good file.
#
$good_file_sid =
  `getfattr --only-values -n security.selinux $basedir/temp_file`;
chop($good_file_sid);

#
# Attempt to access a restricted file as the 'good' domain.  The first test
# hits basic permissions, while the remaining tests hit specific hooks.
#
$result = system "runcon -t test_fileop_t -- touch $basedir/temp_file 2>&1";
ok( $result, 0 );

$result = system
  "runcon -t test_fileop_t -- $basedir/test_seek $basedir/temp_file 2>&1";
ok( $result, 0 );

$result = system
"runcon -t test_fileop_t -- $basedir/test_mmap $basedir/temp_file $good_file_sid 2>&1";
ok( $result, 0 );

$result = system
"runcon -t test_fileop_t -- $basedir/test_mprotect $basedir/temp_file $good_file_sid 2>&1";
ok( $result, 0 );

if ( $isnfs ne "nfs" ) {
    $result = system
"runcon -t test_fileop_t -- $basedir/test_lock $basedir/temp_file $good_file_sid 2>&1";
    ok( $result, 0 );
}

$result = system
"runcon -t test_fileop_t -- $basedir/test_rw $basedir/temp_file $good_file_sid 2>&1";
ok( $result, 0 );

$result = system
  "runcon -t test_fileop_t -- $basedir/test_fcntl $basedir/temp_file 2>&1";
ok( $result, 0 );

#
# Attempt to create a SIGIO as the 'good' domain.
#
$result = system "runcon -t test_fileop_t -- $basedir/test_sigiotask 2>&1";
ok( $result, 0 );

#
# Attempt to access the restricted file as the 'bad' domain. The first test
# hits basic permissions, while the remaining tests hit specific hooks.
#
$result = system "runcon -t test_nofileop_t -- touch $basedir/temp_file 2>&1";
ok($result);

#
# Perform tests for the bad domain.
#
# This seek test will succeed because the llseek hook only verifies that
# the process has access to the file descriptor. In order to test llseek
# properly, a policy change would need to take effect between the time that
# the file was opened and the seek took place. So, for now, we just test
# the basic access which should succeed.
$result = system
  "runcon -t test_nofileop_t -- $basedir/test_seek $basedir/temp_file2 2>&1";
ok( $result, 0 );

$result = system
"runcon -t test_nofileop_t -- $basedir/test_mmap $basedir/temp_file2 $good_file_sid 2>&1";
ok($result);
system "chcon -t nofileop_rw_file_t $basedir/temp_file2 2>&1 > /dev/null";

$result = system
"runcon -t test_nofileop_t -- $basedir/test_mprotect $basedir/temp_file2 $good_file_sid 2>&1";
ok($result);
system "chcon -t nofileop_rw_file_t $basedir/temp_file2 2>&1 > /dev/null";

$result = system
"runcon -t test_nofileop_t -- $basedir/test_lock $basedir/temp_file2 $good_file_sid 2>&1";
ok($result);
system "chcon -t nofileop_rw_file_t $basedir/temp_file2 2>&1 > /dev/null";

$result = system
"runcon -t test_nofileop_t -- $basedir/test_rw $basedir/temp_file2 $good_file_sid 2>&1";
ok($result);
system "chcon -t nofileop_rw_file_t $basedir/temp_file2 2>&1 > /dev/null";

#
# Check the fcntl for the bad domain. This uses the read-only accessable file.
#
$result = system
  "runcon -t test_nofileop_t -- $basedir/test_nofcntl $basedir/temp_file3 2>&1";
ok( $result, 0 );

#
# Attempt to create a SIGIO as the 'bad' domain.
#
$result = system "runcon -t test_nofileop_t -- $basedir/test_sigiotask 2>&1";
ok($result);

#
# Delete the temp files
#
system "rm -f $basedir/temp_file 2>&1";
system "rm -f $basedir/temp_file2 2>&1";
system "rm -f $basedir/temp_file3 2>&1";

exit;
